﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Navigation;
using System.Collections;
using System.Xml.Linq;
using SlamCms.Common;
using System.IO;
using System.ComponentModel;
using Slam.SharePoint;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using Microsoft.SharePoint.Administration;
using Slam.Activation;
using Slam;
using Slam.Events;

namespace SlamCms.SharePoint.Migration
{
	public static class MigrationExtensions
	{
		private static string DefaultFieldSourceId = "http://schemas.microsoft.com/sharepoint";

		private static MigratableContentTypeList Export(this SPContentTypeCollection contentTypes, string scope, MigratableSite site)
		{
			MigratableContentTypeList exportContentTypes = new MigratableContentTypeList();
			foreach (SPContentType contentType in contentTypes)
			{
				if (!SPBuiltInContentTypeId.Contains(contentType.Id) && !contentType.Sealed)
				{
					MigratableContentType exportContentType = contentType.Export(scope, site);
					exportContentTypes.Add(exportContentType);
					if (site != null && exportContentType.ParentScope != scope && exportContentType.ParentScope == site.Url)
					{
						site.ContentTypes.Add(exportContentType);
					}
				}
			}
			return exportContentTypes;
		}

		private static MigratableContentType Export(this SPContentType contentType, string scope, MigratableSite site)
		{
			MigratableContentType exportContentType = new MigratableContentType();
			exportContentType.Name = contentType.Name;
			exportContentType.Group = contentType.Group;
			exportContentType.Scope = scope;
			if (contentType.Parent != null)
			{
				exportContentType.ParentName = contentType.Parent.Name;
				string parentScope = contentType.Parent.Scope.Substring(contentType.ParentWeb.Site.ServerRelativeUrl.Length);
				if (site != null)
				{
					var parentScopeSite = site.GetSite(parentScope);
					if (parentScopeSite == null)
						parentScope = site.Url;
				}
				exportContentType.ParentScope = parentScope;
			}

			foreach (SPField field in contentType.Fields)
			{
				MigratableFieldLink fieldLink = new MigratableFieldLink();
				fieldLink.Title = field.Title;
				fieldLink.StaticName = field.StaticName;
				fieldLink.SourceSite = field.GetSourceSiteUrl(contentType.ParentWeb.Site);
				fieldLink.SourceList = contentType.ParentList == null ? "" : (("{" + contentType.ParentList.ID.ToString() + "}") == field.SourceId ? contentType.ParentList.Title : "");
				exportContentType.FieldLinks.Add(fieldLink);
			}

			return exportContentType;
		}

		public static MigratableField Export(this SPField field, string sourceUrl)
		{
			MigratableField exportField = new MigratableField();
			exportField.Title = field.Title;
			exportField.StaticName = field.StaticName;
			exportField.Source = sourceUrl;
			exportField.Group = field.Group;
			exportField.SchemaXml = field.SchemaXml;
			exportField.LookupList = field.GetLookupListId();
			return exportField;
		}

		public static bool IsModified(this SPField field)
		{
			XElement schema = XElement.Parse(field.SchemaXml);
			return schema.Attribute("Version") != null && field.ParentList != null;
		}

		public static MigratableField Export(this SPField field)
		{
			MigratableField exportField = new MigratableField();
			exportField.Title = field.Title;
			exportField.StaticName = field.StaticName;
			if (field.ParentList != null)
			{
				exportField.Source = field.ParentList.RootFolder.ServerRelativeUrl;
			}
			exportField.Group = field.Group;
			exportField.SchemaXml = field.SchemaXml;
			return exportField;
		}

		private static bool IsLookup(this SPField field)
		{
			bool isLookup = false;
			PropertyDescriptor property = TypeDescriptor.GetProperties(field).Find("LookupList", false);
			if (property != null && property.PropertyType == typeof(string))
			{
				string id = Convert.ToString(property.GetValue(field));
				if (!id.IsNullOrEmpty())
					isLookup = id.IsGuid();
			}
			return isLookup;
		}

		private static string GetLookupListId(this SPField field)
		{
			string listId = "";
			PropertyDescriptor property = TypeDescriptor.GetProperties(field).Find("LookupList", false);
			if (property != null && property.PropertyType == typeof(string))
			{
				string id = Convert.ToString(property.GetValue(field));
				if (!id.IsNullOrEmpty() && id.IsGuid())
					listId = id.TrimStart('{').TrimEnd('}');
			}
			return listId;
		}

		private static MigratableList Export(this SPList list, MigratableSite site, string fileDirectory, bool includeContent)
		{
			SPSite siteCollection = list.ParentWeb.Site;
			MigratableList exportList = new MigratableList();
			exportList.Id = list.ID.ToString();
			exportList.Title = list.Title;
			exportList.Description = list.Description;
			exportList.EnableVersioning = list.EnableVersioning;
			exportList.EnableModeration = list.EnableModeration;
			exportList.ContentTypesEnabled = list.ContentTypesEnabled;
			exportList.OnQuickLaunch = list.OnQuickLaunch;
			exportList.ListTemplateId = (int)list.BaseTemplate;
			if (exportList.ContentTypesEnabled)
			{
				exportList.ContentTypes = list.ContentTypes.Export(list.RootFolder.ServerRelativeUrl.Substring(siteCollection.ServerRelativeUrl.Length), site);
			}
			else if (!SPBuiltInContentTypeId.Contains(list.ContentTypes[0].Id))
			{
				exportList.ContentTypes.Add(list.ContentTypes[0].Export(list.RootFolder.ServerRelativeUrl.Substring(siteCollection.ServerRelativeUrl.Length), site));
			}

			foreach (SPField field in list.Fields)
			{
				// Only check fields that are settable
				if (!field.Sealed && !field.ReadOnlyField && !field.IsSiteColumn(siteCollection))
				{
					string url = field.GetSourceSiteUrl(list.ParentWeb.Site);
					if (!field.IsSiteColumn(list.ParentWeb.Site))
					{
						exportList.Fields.Add(field.Export(url));
					}
					else
					{
						MigratableSite fieldSite = site.GetSite(url);
						if (fieldSite == null)
						{
							site.Fields.Add(field.Export(site.Url));
						}
					}
				}

				//if (!field.Sealed && !field.ReadOnlyField && field.IsLookup())
				//{
				//    MigratableListDependency listDependency = new MigratableListDependency();
				//    listDependency.ListId = field.GetLookupListId();
				//    listDependency.SiteId = "";
				//    if (field is SPFieldLookup)
				//    {
				//        using (SPWeb lookupWeb = siteCollection.AllWebs[((SPFieldLookup)field).LookupWebId])
				//        {
				//            if (site.GetSite(lookupWeb.ServerRelativeUrl.Substring(siteCollection.ServerRelativeUrl.Length)) != null)
				//            {
				//                listDependency.SiteId = lookupWeb.ID.ToString();
				//            }
				//        }
				//    }
				//    if (!exportList.ListDependencies.Any(d => d.SiteId == listDependency.SiteId && d.ListId == listDependency.ListId))
				//        exportList.ListDependencies.Add(listDependency);
				//}
			}
			exportList.Views = list.Views.Export();
			if (includeContent)
				exportList.ListItems = list.Items.Export(fileDirectory);
			return exportList;
		}

		private static List<MigratableListItem> Export(this SPListItemCollection listItems, string fileDirectory)
		{
			List<MigratableListItem> exportListItems = new List<MigratableListItem>();
			SPList list = listItems.List;
			bool hasSlamId = list.Fields.ContainsFieldWithStaticName("SLAM_x0020_ID");
			if (list.BaseTemplate == SPListTemplateType.DocumentLibrary || list.BaseTemplate == SPListTemplateType.PictureLibrary)
			{
				foreach (SPListItem item in list.Folders)
				{
					MigratableFolderListItem listItem = new MigratableFolderListItem();
					listItem.ListRelativeId = item.ID;
					if (hasSlamId)
					{
						listItem.SlamId = Convert.ToString(item["SLAM ID"]);
					}
					listItem.Url = item.Url;
					foreach (SPField field in item.Fields)
					{
						if ((!field.ReadOnlyField && field.CanToggleHidden && field.Type != SPFieldType.Computed && !field.StaticName.StartsWith("_")) || field.StaticName == "ContentType")
						{
							try
							{
								listItem.FieldValues.Add(field.StaticName, item[field.Id]);
							}
							catch { }
						}
					}
					exportListItems.Add(listItem);
				}

				foreach (SPListItem item in list.Items)
				{
					MigratableDocumentListItem listItem = new MigratableDocumentListItem();
					listItem.ListRelativeId = item.ID;
					if (hasSlamId)
					{
						listItem.SlamId = Convert.ToString(item["SLAM ID"]);
					}
					listItem.Url = item.Url;
					listItem.FileId = item.UniqueId.ToString();
					foreach (SPField field in item.Fields)
					{
						if ((!field.ReadOnlyField && field.CanToggleHidden && field.Type != SPFieldType.Computed && !field.StaticName.StartsWith("_")) || field.StaticName == "ContentType")
						{
							try
							{
								listItem.FieldValues.Add(field.StaticName, item[field.Id]);
							}
							catch { }
						}
					}
					exportListItems.Add(listItem);

					Directory.CreateDirectory(Path.Combine(fileDirectory, "Documents\\" + listItem.FileId));
					byte[] fileBytes = item.File.OpenBinary();
					using (FileStream writer = File.Create(Path.Combine(fileDirectory, "Documents\\" + listItem.FileId + "\\" + item.File.Name)))
					{
						writer.Write(fileBytes, 0, fileBytes.Length);
					}
				}
			}
			else
			{
				foreach (SPListItem item in list.Items)
				{
					MigratableListItem listItem = new MigratableListItem();
					listItem.ListRelativeId = item.ID;
					if (hasSlamId)
					{
						listItem.SlamId = Convert.ToString(item["SLAM ID"]);
					}
					foreach (SPField field in item.Fields)
					{
						if ((!field.ReadOnlyField && field.CanToggleHidden && field.Type != SPFieldType.Computed && !field.StaticName.StartsWith("_")) || field.StaticName == "ContentType")
						{
							try
							{
								listItem.FieldValues.Add(field.StaticName, item[field.Id]);
							}
							catch { }
						}
					}
					exportListItems.Add(listItem);
				}
			}
			return exportListItems;
		}

		private static List<MigratableView> Export(this SPViewCollection views)
		{
			List<MigratableView> exportViews = new List<MigratableView>();
			foreach (SPView view in views)
			{
				if (!view.Hidden)
				{
					MigratableView exportView = new MigratableView();
					exportView.Name = view.Title;
					exportView.UrlName = view.Url.Substring(view.Url.LastIndexOf('/') + 1);
					exportView.ViewFields = String.Join(";", view.ViewFields.ToStringCollection().Cast<string>().ToArray());
					exportView.Query = view.Query;
					exportView.Paged = view.Paged;
					exportView.RowLimit = view.RowLimit;
					exportView.Default = view.DefaultView;

					exportViews.Add(exportView);
				}
			}
			return exportViews;
		}

		public static MigratableSite Export(this SPWeb site, string fileDirectory)
		{
			return site.Export(fileDirectory, true);
		}

		public static MigratableSite Export(this SPWeb site, string fileDirectory, bool includeSubsites)
		{
			return site.Export(fileDirectory, includeSubsites, true, null);
		}

		public static MigratableSite Export(this SPWeb site, string fileDirectory, bool includeSubsites, bool includeContent)
		{
			return site.Export(fileDirectory, includeSubsites, includeContent, null);
		}

		public static MigratableSite Export(this SPWeb site, string fileDirectory, bool includeSubsites, bool includeContent, MigratableSite parentSite)
		{
			MigratableSite exportSite = new MigratableSite();
			exportSite.Id = site.ID.ToString();
			exportSite.Title = site.Title;
			exportSite.Description = site.Description;
			exportSite.Url = site.ServerRelativeUrl.Substring(site.Site.ServerRelativeUrl.Length).TrimStart('/');
			exportSite.Template = site.WebTemplate + "#" + site.WebTemplateId.ToString();
			exportSite.Language = site.Language;
			exportSite.UseSharedNavigation = site.Navigation.UseShared;
			exportSite.ParentSite = parentSite;
			string defaultUrl = site.ServerRelativeUrl;
			exportSite.LinkInTopNavigationBar = site.Navigation.UseShared ?
				(site.ParentWeb.Navigation.TopNavigationBar.Cast<SPNavigationNode>().Where(n => n.Url == defaultUrl || n.Url == defaultUrl.TrimEnd('/') + "/default.aspx").FirstOrDefault() != null) :
				(site.Navigation.TopNavigationBar.Cast<SPNavigationNode>().Where(n => n.Url == defaultUrl || n.Url == defaultUrl.TrimEnd('/') + "/default.aspx").FirstOrDefault() != null);

			foreach (SPField field in site.Fields)
			{
				if (!field.Sealed && !field.Hidden)
				{
					XElement schema = XElement.Parse(field.SchemaXml);
					if (!exportSite.Fields.Any(fi => fi.StaticName == field.StaticName) && !field.SourceId.Contains(DefaultFieldSourceId) || (field.SourceId.Contains(DefaultFieldSourceId) && schema.Attribute("Version") != null))
					{
						exportSite.Fields.Add(field.Export(exportSite.Url));
					}
				}
			}

			exportSite.ContentTypes = site.ContentTypes.Export(exportSite.Url, null);
			foreach (SPList list in site.Lists)
			{
				if ((list.BaseTemplate == SPListTemplateType.PictureLibrary || list.BaseTemplate == SPListTemplateType.DocumentLibrary ||
				   list.BaseTemplate == SPListTemplateType.GenericList || list.BaseTemplate == SPListTemplateType.Events) &&
				   !list.Hidden && !list.RootWebOnly)
				{
					exportSite.Lists.Add(list.Export(exportSite, fileDirectory, includeContent));
				}
			}

			if (site.QuickLaunchEnabled)
			{
				exportSite.QuickLaunchItems = site.Navigation.QuickLaunch.Export();
				exportSite.QuickLaunchItems.ForEach(i => i.Url = i.Url.Substring(site.Site.ServerRelativeUrl.Length));
			}

			foreach (DictionaryEntry property in site.Properties)
			{
				if (!property.Key.ToString().StartsWith("vti_"))
					exportSite.Properties.Add(property.Key.ToString(), property.Value);
			}

			foreach (var feature in site.Features.Where(f => f != null && f.Definition != null && !f.Definition.Hidden))
			{
				MigratableFeature exportFeature = new MigratableFeature();
				exportFeature.Id = feature.DefinitionId.ToString();
				exportSite.Features.Add(exportFeature);
			}

			if (includeSubsites)
			{
				foreach (SPWeb subSite in site.Webs)
				{
					exportSite.Sites.Add(subSite.Export(fileDirectory, includeSubsites, includeContent, exportSite));
					subSite.Dispose();
				}
			}
			return exportSite;
		}

		private static List<MigratableQuickLaunchItem> Export(this SPNavigationNodeCollection quickLaunch)
		{
			List<MigratableQuickLaunchItem> exportQuickLaunchItems = new List<MigratableQuickLaunchItem>();
			foreach (SPNavigationNode quickLaunchItem in quickLaunch)
			{
				MigratableQuickLaunchItem newQuickLaunchItem = new MigratableQuickLaunchItem();
				newQuickLaunchItem.Title = quickLaunchItem.Title;
				newQuickLaunchItem.Url = quickLaunchItem.Url;
				newQuickLaunchItem.Children = quickLaunchItem.Children.Export();
				exportQuickLaunchItems.Add(newQuickLaunchItem);
			}
			return exportQuickLaunchItems;
		}

		private static string GetSourceSiteUrl(this SPField field, SPSite siteCollection)
		{
			string sourceUrl = "";
			if (!field.SourceId.IsNullOrEmpty() && field.SourceId.IsGuid() && !field.SourceId.Contains(DefaultFieldSourceId) && field.ParentList == null)
			{
				using (SPWeb site = siteCollection.AllWebs[new Guid(field.SourceId)])
				{
					sourceUrl = site.ServerRelativeUrl.Substring(siteCollection.ServerRelativeUrl.Length).TrimStart('/');
				}
			}
			return sourceUrl;
		}

		private static bool IsSiteColumn(this SPField field, SPSite siteCollection)
		{
			bool siteColumn = false;
			if (!field.SourceId.IsNullOrEmpty() && field.SourceId.IsGuid() && !field.SourceId.Contains(DefaultFieldSourceId) && field.ParentList == null)
			{
				using (SPWeb site = siteCollection.AllWebs[new Guid(field.SourceId)])
				{
					siteColumn = !field.IsModified();
				}
			}
			return siteColumn;
		}

		public static void Import(this SPSite siteCollection, string siteUrl, MigratableSite importSite)
		{
			siteCollection.Import(siteUrl, importSite, "");
		}

		private static Dictionary<Guid, Guid> ImportSites(this SPSite siteCollection, Guid parentWebId, string siteUrl, MigratableSite importSite)
		{
			Dictionary<Guid, Guid> importedSites = new Dictionary<Guid, Guid>();

			Guid importSiteId = new Guid(importSite.Id);
			using (var parentSite = siteCollection.AllWebs[parentWebId])
			{
				if (!siteCollection.AllWebs.Names.Contains(siteUrl) && !importedSites.ContainsKey(importSiteId))
				{
					using (var newSite = siteCollection.AllWebs.Add(siteUrl, importSite.Title, importSite.Description, importSite.Language, importSite.Template, importSite.UseUniquePermissions, false))
					{
						newSite.Navigation.UseShared = importSite.UseSharedNavigation;
						string defaultUrl = newSite.ServerRelativeUrl;
						if (importSite.LinkInTopNavigationBar && importSite.UseSharedNavigation)
						{
							if (parentSite.Navigation.TopNavigationBar.Cast<SPNavigationNode>().Where(n => n.Url == defaultUrl).FirstOrDefault() == null)
							{
								parentSite.Navigation.TopNavigationBar.AddAsLast(new SPNavigationNode(newSite.Title, defaultUrl));
							}
						}
						else if (importSite.LinkInTopNavigationBar && !importSite.UseSharedNavigation)
						{
							if (newSite.Navigation.TopNavigationBar.Cast<SPNavigationNode>().Where(n => n.Url == defaultUrl).FirstOrDefault() == null)
							{
								newSite.Navigation.TopNavigationBar.AddAsLast(new SPNavigationNode(newSite.Title, defaultUrl));
							}
						}

						SPNavigationNode newSiteNode = new SPNavigationNode(importSite.Title, defaultUrl);
						foreach (SPNavigationNode node in parentSite.Navigation.QuickLaunch)
						{
							if (node.Title == "Sites")
							{
								node.Children.AddAsLast(newSiteNode);
								break;
							}
						}
						importedSites.Add(importSiteId, newSite.ID);
						parentSite.Update();
					}
				}

				foreach (var subsite in importSite.Sites)
				{
					string url = importSite.Url.IsNullOrEmpty() ? subsite.Url : subsite.Url.Replace(importSite.Url, siteUrl);
					foreach (var item in siteCollection.ImportSites(parentSite.ID, url, subsite))
					{
						if (!importedSites.ContainsKey(item.Key))
						{
							importedSites.Add(item.Key, item.Value);
						}
					}
				}
			}
			return importedSites;
		}

		private static void ImportSiteColumns(this SPSite siteCollection, string siteUrl, MigratableSite importSite, Dictionary<Guid, Guid> idLookup)
		{
			using (SPSite newSiteCollection = new SPSite(siteCollection.ID))
			{
				Guid importSiteId = new Guid(importSite.Id);
				using (var site = newSiteCollection.AllWebs[siteUrl])
				{
					site.AllowUnsafeUpdates = true;
					foreach (MigratableField importField in importSite.Fields)
					{
						var field = site.Fields.Cast<SPField>().Where(o => o.StaticName.Equals(importField.StaticName)).FirstOrDefault();

						if (field == null)
						{
							XElement importFieldSchema = XElement.Parse(importField.SchemaXml);

							if (importFieldSchema.Attribute("ID") != null)
								importFieldSchema.Attribute("ID").Remove();
							if (importFieldSchema.Attribute("DisplayName") != null)
								importFieldSchema.Attribute("DisplayName").Value = importField.Title;
							if (importFieldSchema.Attribute("StaticName") != null)
								importFieldSchema.Attribute("StaticName").Value = importField.StaticName;
							if (importFieldSchema.Attribute("Group") != null)
								importFieldSchema.Attribute("Group").Value = importField.Group;
							if (importFieldSchema.Attribute("Version") != null)
								importFieldSchema.Attribute("Version").Remove();
							if (importFieldSchema.Attribute("SourceID") != null)
								importFieldSchema.Attribute("SourceID").Remove();

							string schemaXml = importFieldSchema.ToString();
							foreach (KeyValuePair<Guid, Guid> item in idLookup)
							{
								schemaXml = Regex.Replace(schemaXml, item.Key.ToString(), item.Value.ToString(), RegexOptions.IgnoreCase);
							}

							site.Fields.AddFieldAsXml(schemaXml, false, SPAddFieldOptions.AddToNoContentType);
						}
						else if (!importField.Equals(field))
						{
							XElement fieldSchema = XElement.Parse(field.SchemaXml);
							XElement importFieldSchema = XElement.Parse(importField.SchemaXml);

							importFieldSchema.Attribute("ID").SetValue(fieldSchema.Attribute("ID").Value);
							importFieldSchema.Attribute("SourceID").SetValue(fieldSchema.Attribute("SourceID").Value);

							field.SchemaXml = importFieldSchema.ToString();
							foreach (KeyValuePair<Guid, Guid> item in idLookup)
							{
								field.SchemaXml = Regex.Replace(field.SchemaXml, item.Key.ToString(), item.Value.ToString(), RegexOptions.IgnoreCase);
							}
							field.Update(true);
						}
					}

					foreach (var subsite in importSite.Sites)
					{
						string url = importSite.Url.IsNullOrEmpty() ? subsite.Url : subsite.Url.Replace(importSite.Url, siteUrl);
						newSiteCollection.ImportSiteColumns(url, subsite, idLookup);
					}
				}
			}
		}

		private static void ImportSiteContentTypes(this SPSite siteCollection, string siteUrl, MigratableSite importSite)
		{
			using (SPSite newSiteCollection = new SPSite(siteCollection.ID))
			{
				using (var site = newSiteCollection.AllWebs[siteUrl])
				{
					var parentsSourceUrls = importSite.ContentTypes.Select(o => o.ParentScope).Distinct().ToArray();
					var fieldsSourceUrl = importSite.ContentTypes.Select(x => x.FieldLinks.Select(y => y.SourceSite).Distinct().ToArray()).Distinct().ToList();
					List<String> temp = new List<string>();
					foreach (Array o in fieldsSourceUrl)
						temp.AddRange(o.Cast<string>().ToList());

					var sourceUrls = parentsSourceUrls.Concat(temp.ToArray()).Distinct().ToArray();
					var sources = site.Site.AllWebs.Where(o => sourceUrls.Contains(o.ServerRelativeUrl.Substring(o.Site.ServerRelativeUrl.Length).TrimStart('/'))).ToList();

					foreach (MigratableContentType importContentType in importSite.ContentTypes)
					{
						var contentType = site.ContentTypes[importContentType.Name];
						if (contentType != null && !contentType.Sealed)
						{
							//Update Content Type in case it is needed. Just Incremental Update
							UpdateContentType(site.ContentTypes[importContentType.Name], importContentType, sources);
						}
						else if (contentType == null)
						{
							//Create Content Type
							AddContentType(site.ContentTypes, importContentType, sources, true);
						}
					}

					foreach (var subsite in importSite.Sites)
					{
						string url = importSite.Url.IsNullOrEmpty() ? subsite.Url : subsite.Url.Replace(importSite.Url, siteUrl);
						newSiteCollection.ImportSiteContentTypes(url, subsite);
					}
				}
			}
		}

		private static void ImportQuicklaunches(this SPSite siteCollection, string siteUrl, MigratableSite importSite)
		{
			using (SPSite newSiteCollection = new SPSite(siteCollection.ID))
			{
				using (var site = newSiteCollection.AllWebs[siteUrl])
				{
					site.AllowUnsafeUpdates = true;
					if (site.QuickLaunchEnabled && importSite.QuickLaunchItems.Count > 0)
					{
						for (int i = site.Navigation.QuickLaunch.Count - 1; i > -1; i--)
						{
							site.Navigation.QuickLaunch[i].Delete();
						}

						foreach (var item in importSite.QuickLaunchItems)
						{
							ImportQuickLaunchItem(item, site.Navigation.QuickLaunch, siteCollection.ServerRelativeUrl);
						}
					}

					foreach (var subsite in importSite.Sites)
					{
						string url = importSite.Url.IsNullOrEmpty() ? subsite.Url : subsite.Url.Replace(importSite.Url, siteUrl);
						newSiteCollection.ImportQuicklaunches(url, subsite);
					}
				}
			}
		}

		private static void ImportSiteProperties(this SPSite siteCollection, string siteUrl, MigratableSite importSite)
		{
			using (SPSite newSiteCollection = new SPSite(siteCollection.ID))
			{
				using (var site = newSiteCollection.AllWebs[siteUrl])
				{
					site.AllowUnsafeUpdates = true;

					foreach (var property in importSite.Properties)
					{
						if (site.Properties.ContainsKey(property.Key))
						{
							site.Properties[property.Key] = Convert.ToString(property.Value);
						}
						else
						{
							site.Properties.Add(property.Key, Convert.ToString(property.Value));
						}
					}
					site.Properties.Update();


					foreach (var subsite in importSite.Sites)
					{
						string url = importSite.Url.IsNullOrEmpty() ? subsite.Url : subsite.Url.Replace(importSite.Url, siteUrl);
						newSiteCollection.ImportSiteProperties(url, subsite);
					}
				}
			}
		}

		private static void ImportSiteFeatures(this SPSite siteCollection, string siteUrl, MigratableSite importSite)
		{
			using (SPSite newSiteCollection = new SPSite(siteCollection.ID))
			{
				using (var site = newSiteCollection.AllWebs[siteUrl])
				{
					foreach (var feature in importSite.Features)
					{
						if (feature.Id.IsGuid())
						{
							Guid featureId = new Guid(feature.Id);
							if (!site.Features.Cast<SPFeature>().Any(f => f.DefinitionId == featureId))
							{
								site.Features.Add(featureId);
							}
						}
					}

					foreach (var subsite in importSite.Sites)
					{
						string url = importSite.Url.IsNullOrEmpty() ? subsite.Url : subsite.Url.Replace(importSite.Url, siteUrl);
						newSiteCollection.ImportSiteFeatures(url, subsite);
					}
				}
			}
		}

		private static Dictionary<Guid, Guid> ImportLists(this SPSite siteCollection, string siteUrl, MigratableSite importSite, bool createOnly, Dictionary<Guid, Guid> idLookup)
		{
			Dictionary<Guid, Guid> importedLists = new Dictionary<Guid, Guid>();
			using (SPSite newSiteCollection = new SPSite(siteCollection.ID))
			{
				using (var site = newSiteCollection.AllWebs[siteUrl])
				{
					foreach (MigratableList importList in importSite.Lists)
					{
						Guid importListId = new Guid(importList.Id);
						var list = site.Lists.Cast<SPList>().Where(o => o.Title.Equals(importList.Title)).FirstOrDefault();
						if (list == null)
						{
							var listId = site.Lists.Add(importList.Title, importList.Description, (SPListTemplateType)importList.ListTemplateId);
							list = site.Lists[listId];
						}

						if (!importedLists.ContainsKey(importListId))
						{
							importedLists.Add(importListId, list.ID);
						}

						list.OnQuickLaunch = importList.OnQuickLaunch;
						list.EnableVersioning = importList.EnableVersioning;
						list.EnableModeration = importList.EnableModeration;
						list.ContentTypesEnabled = importList.ContentTypesEnabled;
						list.Update();

						//foreach (var listDependency in importList.ListDependencies)
						//{
						//    if (!_importIdLookup.ContainsKey(new Guid(listDependency.ListId)))
						//    {

						//    }
						//}

						if (!createOnly)
						{
							UpdateListContentTypes(list, importList.ContentTypes);
							list.Update();
							SPFolder rootFolder = list.RootFolder;
							var contentTypeList = rootFolder.ContentTypeOrder;
							for (int i = 0; i < contentTypeList.Count; i++)
							{
								if (!importList.ContentTypes.Any(c => c.Name.Equals(contentTypeList[i].Name)))
								{
									contentTypeList.RemoveAt(i);
									i--;
								}
							}
							rootFolder.UniqueContentTypeOrder = contentTypeList;
							rootFolder.Update();

							site.AllowUnsafeUpdates = true;

							foreach (MigratableField importField in importList.Fields)
							{
								var field = list.Fields.Cast<SPField>().Where(o => o.StaticName.Equals(importField.StaticName)).FirstOrDefault();

								if (field == null)
								{
									XElement importFieldSchema = XElement.Parse(importField.SchemaXml);

									if (importFieldSchema.Attribute("ID") != null)
										importFieldSchema.Attribute("ID").Remove();
									if (importFieldSchema.Attribute("DisplayName") != null)
										importFieldSchema.Attribute("DisplayName").Value = importField.Title;
									if (importFieldSchema.Attribute("StaticName") != null)
										importFieldSchema.Attribute("StaticName").Value = importField.StaticName;
									if (importFieldSchema.Attribute("Group") != null)
										importFieldSchema.Attribute("Group").Value = importField.Group;

									string schemaXml = importFieldSchema.ToString();
									foreach (KeyValuePair<Guid, Guid> item in idLookup)
									{
										schemaXml = Regex.Replace(schemaXml, item.Key.ToString(), item.Value.ToString(), RegexOptions.IgnoreCase);
									}

									list.Fields.AddFieldAsXml(schemaXml, false, list.ContentTypesEnabled ? SPAddFieldOptions.AddToNoContentType : SPAddFieldOptions.AddToDefaultContentType);
								}
								else if (!importField.Equals(field))
								{
									XElement fieldSchema = XElement.Parse(field.SchemaXml);
									XElement importFieldSchema = XElement.Parse(importField.SchemaXml);

									importFieldSchema.Attribute("ID").SetValue(fieldSchema.Attribute("ID").Value);
									importFieldSchema.Attribute("SourceID").SetValue(fieldSchema.Attribute("SourceID").Value);

									field.SchemaXml = importFieldSchema.ToString();
									foreach (KeyValuePair<Guid, Guid> item in idLookup)
									{
										field.SchemaXml = Regex.Replace(field.SchemaXml, item.Key.ToString(), item.Value.ToString(), RegexOptions.IgnoreCase);
									}
									field.Update();
								}
							}
							list.Update();

							RemoveListExclusiveFields(list, importList.ContentTypes, importList.Fields);
							list.Update();
							UpdateViews(importList.Views, list);
							list.Update();
						}
					}

					foreach (var subsite in importSite.Sites)
					{
						string url = importSite.Url.IsNullOrEmpty() ? subsite.Url : subsite.Url.Replace(importSite.Url, siteUrl);
						foreach (var item in newSiteCollection.ImportLists(url, subsite, createOnly, idLookup))
						{
							if (!importedLists.ContainsKey(item.Key))
							{
								importedLists.Add(item.Key, item.Value);
							}
						}
					}
				}
			}
			return importedLists;
		}

		private static Dictionary<Guid, Dictionary<int, int>> ImportListItems(this SPSite siteCollection, string siteUrl, MigratableSite importSite, string fileDirectory, Dictionary<Guid, Guid> idLookup, bool slamItems)
		{
			return ImportListItems(siteCollection, siteUrl, importSite, fileDirectory, idLookup, slamItems, null);
		}

		private static Dictionary<Guid, Dictionary<int, int>> ImportListItems(this SPSite siteCollection, string siteUrl, MigratableSite importSite, string fileDirectory, Dictionary<Guid, Guid> idLookup, bool slamItems, Action<string> logAction)
		{
			Dictionary<Guid, Dictionary<int, int>> importedListItems = new Dictionary<Guid, Dictionary<int, int>>();
			foreach (MigratableList importList in importSite.Lists)
			{
				var listItems = siteCollection.ImportListListItems(siteUrl, importSite, importList, fileDirectory, idLookup, 0, slamItems, logAction);
				foreach (var item in listItems)
				{
					if (!importedListItems.ContainsKey(item.Key))
					{
						importedListItems.Add(item.Key, item.Value);
					}
					else
					{
						foreach (var importedItem in item.Value)
						{
							if (!importedListItems[item.Key].ContainsKey(importedItem.Key))
							{
								importedListItems[item.Key].Add(importedItem.Key, importedItem.Value);
							}
						}
					}
				}
			}

			foreach (var subsite in importSite.Sites)
			{
				string url = importSite.Url.IsNullOrEmpty() ? subsite.Url : subsite.Url.Replace(importSite.Url, siteUrl);
				foreach (var item in siteCollection.ImportListItems(url, subsite, fileDirectory, idLookup, slamItems, logAction))
				{
					if (!importedListItems.ContainsKey(item.Key))
					{
						importedListItems.Add(item.Key, item.Value);
					}
					else
					{
						foreach (var importedItem in item.Value)
						{
							if (!importedListItems[item.Key].ContainsKey(importedItem.Key))
							{
								importedListItems[item.Key].Add(importedItem.Key, importedItem.Value);
							}
						}
					}
				}
			}
			return importedListItems;
		}

		private static Dictionary<Guid, Dictionary<int, int>> ImportListListItems(this SPSite siteCollection, string siteUrl, MigratableSite importSite, MigratableList importList, string fileDirectory, Dictionary<Guid, Guid> idLookup, int idFilter, bool slamItems)
		{
			return ImportListListItems(siteCollection, siteUrl, importSite, importList, fileDirectory, idLookup, idFilter, slamItems, null);
		}

		private static Dictionary<Guid, Dictionary<int, int>> ImportListListItems(this SPSite siteCollection, string siteUrl, MigratableSite importSite, MigratableList importList, string fileDirectory, Dictionary<Guid, Guid> idLookup, int idFilter, bool slamItems, Action<string> logAction)
		{
			EventUtility eventUtility = new EventUtility();
			eventUtility.DisableEventHandlers();
			Dictionary<Guid, Dictionary<int, int>> importedListItems = new Dictionary<Guid, Dictionary<int, int>>();
			using (SPSite newSiteCollection = new SPSite(siteCollection.ID))
			{
				using (var site = newSiteCollection.AllWebs[siteUrl])
				{
					Guid importListId = new Guid(importList.Id);
					var list = site.Lists.Cast<SPList>().Where(o => o.Title.Equals(importList.Title)).FirstOrDefault();

					if (list != null)
					{
						if (!importedListItems.ContainsKey(list.ID))
							importedListItems.Add(list.ID, new Dictionary<int, int>());

						if (logAction != null)
							logAction.Invoke("Importing List: " + list.Title);
						bool hasSlamId = list.Fields.ContainsFieldWithStaticName("SLAM_x0020_ID");
						slamItems = slamItems && list.EventReceivers.Cast<SPEventReceiverDefinition>().Any(e => e.Name.StartsWith("SLAM"));

						int j = 0;
						foreach (MigratableListItem item in importList.ListItems)
						{
							j++;

							if (logAction != null)
								logAction.Invoke("Importing List Item " + j + " of " + importList.ListItems.Count);

							bool newItem = false;
							if (idFilter == 0 || (idFilter > 0 && item.ListRelativeId == idFilter))
							{
								SPListItem listItem = null;

								if (!item.SlamId.IsNullOrEmpty())
								{
									try
									{
										listItem = list.GetItemBySlamId(item.SlamId);
									}
									catch { }
								}

								if (listItem == null)
								{
									if (item is MigratableDocumentListItem)
									{
										MigratableDocumentListItem documentItem = (MigratableDocumentListItem)item;

										string fileUrl = documentItem.Url.Substring(documentItem.Url.IndexOf("/") + 1);
										string fileName = "";
										string[] fileParts = fileUrl.Split('/');

										SPFolder fileFolder = list.RootFolder;
										SPFolder previousFolder = list.RootFolder;

										if (fileParts.Length > 1)
										{
											fileName = fileParts.Last();
											fileParts = fileParts.Take(fileParts.Length - 1).ToArray();

											foreach (string fileSubFolder in fileParts)
											{
												try
												{
													fileFolder = fileFolder.SubFolders.Cast<SPFolder>().Where(f => f.Name.Equals(fileSubFolder, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
												}
												catch { }

												if (fileFolder == null || !fileFolder.Exists)
												{
													fileFolder = previousFolder.SubFolders.Add(fileSubFolder);
													if (list.EnableModeration)
													{
														fileFolder.Item.Update();

														SPListItem folderListItem = fileFolder.Item;
														fileFolder.Item.ModerationInformation.Status = SPModerationStatusType.Approved;
														fileFolder.Item.Update();
													}
												}
												previousFolder = fileFolder;
											}
										}
										else
										{
											fileName = fileUrl;
										}

										if (fileFolder != null && fileFolder.Exists)
										{
											using (FileStream fileStream = File.Open(Path.Combine(fileDirectory, "Documents\\" + documentItem.FileId + "\\" + fileName), FileMode.Open))
											{
												SPFile newFile = null;
												try
												{
													newFile = fileFolder.Files.Add(fileName, fileStream);
													newFile.Update();
												}
												catch
												{
													fileFolder.Files.Delete(fileName);
													newFile = fileFolder.Files.Add(fileName, fileStream);
													newFile.Update();
												}

												if (newFile != null)
												{
													listItem = newFile.Item;
												}
											}
										}
									}
									else if (item is MigratableFolderListItem)
									{
										MigratableFolderListItem folderItem = (MigratableFolderListItem)item;

										string folderUrl = folderItem.Url.Substring(folderItem.Url.IndexOf("/") + 1);
										string folderName = "";
										string[] folderParts = folderUrl.Split('/');

										SPFolder folder = list.RootFolder;
										SPFolder previousFolder = list.RootFolder;

										if (folderParts.Length > 1)
										{
											folderName = folderParts.Last();
										}
										else
										{
											folderName = folderUrl;
										}

										if (folderParts.Length > 1)
										{
											folderParts = folderParts.Take(folderParts.Length - 1).ToArray();

											foreach (string fileSubFolder in folderParts)
											{
												try
												{
													folder = folder.SubFolders.Cast<SPFolder>().Where(f => f.Name.Equals(fileSubFolder, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
												}
												catch { }

												if (folder == null || !folder.Exists)
												{
													folder = previousFolder.SubFolders.Add(fileSubFolder);
													if (list.EnableModeration)
													{
														folder.Item.Update();

														SPListItem folderListItem = folder.Item;
														folder.Item.ModerationInformation.Status = SPModerationStatusType.Approved;
														folder.Item.Update();
													}
												}
												previousFolder = folder;
											}
										}

										if (previousFolder != null && previousFolder.Exists)
										{
											try
											{
												folder = previousFolder.SubFolders.Cast<SPFolder>().Where(f => f.Name.Equals(folderName, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
											}
											catch { }
											if (folder == null || !folder.Exists)
											{
												folder = previousFolder.SubFolders.Add(folderName);
												if (list.EnableModeration)
												{
													folder.Item.Update();

													SPListItem folderListItem = folder.Item;
													folder.Item.ModerationInformation.Status = SPModerationStatusType.Approved;
													folder.Item.Update();
												}
											}

											if (folder != null)
											{
												listItem = folder.Item;
											}
										}
									}

									if (listItem == null)
									{
										listItem = list.Items.Add();
										if (hasSlamId)
										{
											listItem["SLAM ID"] = String.IsNullOrEmpty(item.SlamId) ? listItem.GetUniqueId(true, false) : item.SlamId;
										}
										newItem = true;
									}

								}

								if (item.FieldValues.ContainsKey("ContentType") && list.ContentTypes[item.FieldValues["ContentType"].ToString()] != null)
									listItem["ContentTypeId"] = list.ContentTypes[item.FieldValues["ContentType"].ToString()].Id;

								foreach (KeyValuePair<string, object> fieldValue in item.FieldValues)
								{
									var field = list.Fields.Cast<SPField>().Where(f => f.StaticName.Equals(fieldValue.Key)).FirstOrDefault();
									if (field != null)
									{
										object value = fieldValue.Value;
										if (!value.ToString().IsNullOrEmpty() && field.IsLookup())
										{
											SPFieldLookupValueCollection lookupFieldValues = new SPFieldLookupValueCollection(value.ToString());
											SPFieldLookupValueCollection newLookupFieldValues = new SPFieldLookupValueCollection();

											Guid lookupListId = new Guid(field.GetLookupListId());
											if (lookupListId != Guid.Empty)
											{
												if (importedListItems.ContainsKey(lookupListId))
												{
													foreach (var lookupFieldValue in lookupFieldValues)
													{
														if (importedListItems.ContainsKey(lookupListId) && importedListItems[lookupListId].ContainsKey(lookupFieldValue.LookupId))
														{
															newLookupFieldValues.Add(new SPFieldLookupValue(importedListItems[lookupListId][lookupFieldValue.LookupId], lookupFieldValue.LookupValue));
														}
														else
														{
															var previousListId = idLookup.Where(i => i.Value == lookupListId).FirstOrDefault().Key;
															var previousList = importSite.GetList(previousListId);
															if (previousList != null)
															{
																MigratableSite subsite = importSite.GetListSite(previousListId);
																string url = importSite.Url.IsNullOrEmpty() ? subsite.Url : subsite.Url.Replace(importSite.Url, siteUrl);
																foreach (var importedItem in newSiteCollection.ImportListListItems(url, importSite, previousList, fileDirectory, idLookup, lookupFieldValue.LookupId, slamItems, logAction))
																{
																	if (!importedListItems.ContainsKey(importedItem.Key))
																	{
																		importedListItems.Add(importedItem.Key, importedItem.Value);
																	}
																	else
																	{
																		foreach (var importedListItem in importedItem.Value)
																		{
																			if (!importedListItems[importedItem.Key].ContainsKey(importedListItem.Key))
																			{
																				importedListItems[importedItem.Key].Add(importedListItem.Key, importedListItem.Value);
																			}
																		}
																	}
																}

																if (importedListItems.ContainsKey(lookupListId) && importedListItems[lookupListId].ContainsKey(lookupFieldValue.LookupId))
																	newLookupFieldValues.Add(new SPFieldLookupValue(importedListItems[lookupListId][lookupFieldValue.LookupId], lookupFieldValue.LookupValue));
															}
														}
													}
												}
												else
												{

												}
											}
										}
										if (fieldValue.Value is string)
										{
											foreach (KeyValuePair<Guid, Guid> lookupItem in idLookup)
											{
												value = value.ToString().Replace(lookupItem.Key.ToString(), lookupItem.Value.ToString());
											}
										}
										listItem[field.Id] = value;
									}
								}
								listItem.Update();

								if (list.EnableModeration)
								{
									listItem.ModerationInformation.Status = SPModerationStatusType.Approved;
									listItem.Update();
								}

								if (slamItems)
									listItem.SlamUpdate(false, false, false, site.CurrentUser.LoginName, newItem);

								if (!importedListItems[list.ID].ContainsKey(item.ListRelativeId))
									importedListItems[list.ID].Add(item.ListRelativeId, listItem.ID);
								else
									importedListItems[list.ID][item.ListRelativeId] = listItem.ID;
							}
						}
					}

				}
			}
			eventUtility.EnableEventHandlers();
			return importedListItems;
		}

		public static void Import(this SPSite siteCollection, string siteUrl, MigratableSite importSite, string fileDirectory)
		{
			siteCollection.Import(siteUrl, importSite, fileDirectory, false);
		}

		public static void Import(this SPSite siteCollection, string siteUrl, MigratableSite importSite, string fileDirectory, bool activateSlam)
		{
			siteCollection.Import(siteUrl, importSite, fileDirectory, false, null);
		}

		public static void Import(this SPSite siteCollection, string siteUrl, MigratableSite importSite, string fileDirectory, bool activateSlam, Action<string> logAction)
		{
			Dictionary<Guid, Guid> idLookup = new Dictionary<Guid, Guid>();
			Dictionary<Guid, Dictionary<int, int>> itemIdLookup = new Dictionary<Guid, Dictionary<int, int>>();
			Dictionary<Guid, Guid> importedSites = new Dictionary<Guid, Guid>();
			Dictionary<Guid, Guid> importedLists = new Dictionary<Guid, Guid>();
			using (SPWeb parentSite = siteCollection.OpenWeb())
			{
				if (logAction != null)
					logAction.Invoke("Importing Sites...");
				importedSites = siteCollection.ImportSites(parentSite.ID, siteUrl, importSite);
				if (logAction != null)
					logAction.Invoke("Importing Lists...");
				importedLists = siteCollection.ImportLists(siteUrl, importSite, true, idLookup);

				foreach (var item in importedSites)
				{
					if (!idLookup.ContainsKey(item.Key))
						idLookup.Add(item.Key, item.Value);
				}
				foreach (var item in importedLists)
				{
					if (!idLookup.ContainsKey(item.Key))
						idLookup.Add(item.Key, item.Value);
				}

				if (logAction != null)
					logAction.Invoke("Importing Site Columns...");
				siteCollection.ImportSiteColumns(siteUrl, importSite, idLookup);
				if (logAction != null)
					logAction.Invoke("Importing Site Content Types...");
				siteCollection.ImportSiteContentTypes(siteUrl, importSite);

				if (activateSlam)
				{
					if (logAction != null)
						logAction.Invoke("Activating SLAM...");
					IActivator activator = ComponentService.GetInstance<IActivator>();
					using (SPWeb rootWeb = siteCollection.RootWeb)
					{
						if (rootWeb.Properties["SLAMLastActivationDate"] != null)
						{
							activator.Deactivate(rootWeb.Url);
							rootWeb.Properties["SLAMLastActivationDate"] = DateTime.Now.ToString();
							rootWeb.Properties.Update();
						}
						else
						{
							rootWeb.Properties.Add("SLAMLastActivationDate", DateTime.Now.ToString());
							rootWeb.Properties.Update();
						}

						activator.Activate(rootWeb.Url);
						ComponentService.ClearInstances();
					}
				}
			}

			using (SPWeb parentSite = siteCollection.OpenWeb())
			{
				if (logAction != null)
					logAction.Invoke("Importing Lists...");
				importedLists = siteCollection.ImportLists(siteUrl, importSite, false, idLookup);
				if (logAction != null)
					logAction.Invoke("Importing List Items...");
				itemIdLookup = siteCollection.ImportListItems(siteUrl, importSite, fileDirectory, idLookup, activateSlam, logAction);

				if (logAction != null)
					logAction.Invoke("Importing Quick Launches...");
				siteCollection.ImportQuicklaunches(siteUrl, importSite);
				if (logAction != null)
					logAction.Invoke("Importing Site Properties...");
				siteCollection.ImportSiteProperties(siteUrl, importSite);
				if (logAction != null)
					logAction.Invoke("Importing Site Features...");
				siteCollection.ImportSiteFeatures(siteUrl, importSite);
			}
		}

		private static void RemoveListExclusiveFields(SPList list, MigratableContentTypeList contentTypes, MigratableFieldList fields)
		{
			var fieldNames = fields.Select(o => o.StaticName).ToList();
			List<string> temp = new List<string>();
			foreach (MigratableContentType contentType in contentTypes)
			{
				temp.AddRange(contentType.FieldLinks.Select(o => o.StaticName).ToList());
			}
			var fieldLinks = temp.Distinct().ToList();
			var notLinkedFields = fieldNames.Except(fieldLinks).Select(s => s.Length > 32 ? s.Substring(0, 32) : s).ToArray();
			var contentTypesWithExclusiveFields = list.ContentTypes.Cast<SPContentType>().Where(o => !o.Sealed && o.FieldLinks.Cast<SPFieldLink>().Any(y => notLinkedFields.Contains(y.Name))).ToList();

			foreach (SPContentType contentType in contentTypesWithExclusiveFields)
			{
				var links = contentType.FieldLinks.Cast<SPFieldLink>().Where(o => notLinkedFields.Contains(o.Name)).ToList();

				foreach (SPFieldLink link in links)
					contentType.FieldLinks.Delete(link.Id);

				contentType.Update();
			}
		}

		private static void UpdateListContentTypes(SPList list, MigratableContentTypeList importContentTypes)
		{
			// Get the needed SPWeb just one time at the beginning
			var parentsSourceUrls = importContentTypes.Select(o => o.ParentScope).Distinct().ToArray();
			var fieldsSourceUrl = importContentTypes.Select(x => x.FieldLinks.Select(y => y.SourceSite).Distinct().ToArray()).Distinct().ToList();
			List<String> temp = new List<string>();
			foreach (Array o in fieldsSourceUrl)
				temp.AddRange(o.Cast<string>().ToList());

			var sourceUrls = parentsSourceUrls.Concat(temp.ToArray()).Distinct().ToArray();
			var sources = list.ParentWeb.Site.AllWebs.Where(o => sourceUrls.Contains(o.ServerRelativeUrl.Substring(o.Site.ServerRelativeUrl.Length).TrimStart('/'))).ToList();

			foreach (MigratableContentType iCT in importContentTypes)
			{
				var ct = list.ContentTypes[iCT.Name];

				if (ct != null && !ct.Sealed)
				{
					//Update Content Type in case it is needed. Just Incremental Update
					UpdateContentType(list.ContentTypes[iCT.Name], iCT, sources);
				}
				else if (ct == null)
				{
					//Create Content Type
					AddContentType(list.ContentTypes, iCT, sources, iCT.FieldLinks.Count > 0);
				}
			}
		}

		private static void UpdateViews(List<MigratableView> importViews, SPList list)
		{
			foreach (MigratableView iView in importViews)
			{
				var view = list.Views.Cast<SPView>().Where(o => o.Title.Equals(iView.Name)).FirstOrDefault();
				if (view == null)
				{
					// Add the view
					AddView(list, iView);
				}
				else
				{
					// Validate if the view must be replace it or not.
					if (iView.Replace)
					{
						list.Views.Delete(view.ID);
						AddView(list, iView);
					}
				}
			}
		}

		private static void AddView(SPList list, MigratableView importView)
		{
			StringCollection viewFields = new StringCollection();
			foreach (string s in importView.ViewFields.Split(';'))
				viewFields.Add(s);

			string title = importView.UrlName.Remove(importView.UrlName.IndexOf(".aspx"));

			var view = list.Views.Add(title, viewFields, importView.Query, importView.RowLimit, importView.Paged, importView.Default);
			// In some cases the title might be different to the url name that was use to create the view
			if (!title.Equals(importView.Name))
			{
				view.Title = importView.Name;
				view.Update();
			}
		}

		private static void UpdateContentType(SPContentType contentType, MigratableContentType importContentType, List<SPWeb> sources)
		{
			if (!importContentType.Group.Equals(contentType.Group))
				contentType.Group = importContentType.Group;

			UpdateFieldLinks(contentType, importContentType, sources);
			contentType.Update();
		}

		private static void AddContentType(SPContentTypeCollection contentTypes, MigratableContentType importContentType, List<SPWeb> sources, bool addFieldLinks)
		{
			var parentSourceWeb = sources.Where(o => o.ServerRelativeUrl.Substring(o.Site.ServerRelativeUrl.Length).TrimStart('/').Equals(importContentType.ParentScope)).FirstOrDefault();
			if (parentSourceWeb != null)
			{
				var parentContentType = parentSourceWeb.ContentTypes.Cast<SPContentType>().Where(o => o.Name.Equals(importContentType.ParentName)).FirstOrDefault();
				if (parentContentType != null)
				{
					SPContentType contentType = new SPContentType(parentContentType, contentTypes, importContentType.Name);
					contentType = contentTypes.Add(contentType);
					contentType.Group = importContentType.Group;
					// Clean all the previous fields
					if (addFieldLinks)
					{
						var fieldIds = contentType.FieldLinks.Cast<SPFieldLink>().Select(o => o.Id).ToList();
						foreach (Guid id in fieldIds)
							contentType.FieldLinks.Delete(id);
						AddFieldLinks(contentType, importContentType, sources);
					}
					contentType.Update();
				}
			}
		}

		private static void UpdateFieldLinks(SPContentType contentType, MigratableContentType importContentType, List<SPWeb> sources)
		{
			foreach (MigratableFieldLink iFieldLink in importContentType.FieldLinks)
			{
				var fieldLink = contentType.FieldLinks.Cast<SPFieldLink>().Where(o => o.Name.Equals(iFieldLink.Title) || o.Name.Equals(iFieldLink.StaticName)).FirstOrDefault();
				if (fieldLink == null)
					AddFieldLink(contentType, iFieldLink, sources);
			}

		}

		private static void AddFieldLinks(SPContentType contentType, MigratableContentType importContentType, List<SPWeb> sources)
		{
			foreach (MigratableFieldLink iFieldLink in importContentType.FieldLinks)
			{
				AddFieldLink(contentType, iFieldLink, sources);
			}
		}

		private static void AddFieldLink(SPContentType contentType, MigratableFieldLink iFieldLink, List<SPWeb> sources)
		{
			//If the source is empty the field belongs to the list where the content Type is added
			SPFieldCollection fieldCollection = null;

			if (!String.IsNullOrEmpty(iFieldLink.SourceList))
			{
				//The content type is contained on a List. Verify that is the case.
				if (contentType.ParentList != null)
				{
					//field = contentType.ParentList.Fields.Cast<SPField>().Where(o => o.StaticName.Equals(iFieldLink.StaticName)).FirstOrDefault();
					fieldCollection = contentType.ParentList.Fields;
				}
				else
				{
					//Here should be an exception or Log that the xml data is not correct. All FieldLinks have source except the ones that reference to a list.
				}
			}
			else
			{
				// The field is from a site
				var fieldSourceWeb = sources.Where(o => o.ServerRelativeUrl.Substring(o.Site.ServerRelativeUrl.Length).TrimStart('/').Equals(iFieldLink.SourceSite)).FirstOrDefault();
				if (fieldSourceWeb != null)
				{
					//field = fieldSourceWeb.Fields.Cast<>
					fieldCollection = fieldSourceWeb.Fields;
				}
				else
				{
					//Exception or log the error.
				}
			}

			//Obtain the Field to link to the content type
			var field = fieldCollection.Cast<SPField>().Where(o => o.StaticName.Equals(iFieldLink.StaticName)).FirstOrDefault();
			if (field != null && !contentType.FieldLinks.Cast<SPFieldLink>().Any(f => f.Id == field.Id))
			{
				contentType.FieldLinks.Add(new SPFieldLink(field));
			}

		}

		private static void ImportQuickLaunchItem(MigratableQuickLaunchItem quickLaunchItem, SPNavigationNodeCollection quickLaunch, string siteCollectionUrl)
		{
			SPNavigationNode newQuickLaunchNode = null;
			try
			{
				newQuickLaunchNode = new SPNavigationNode(quickLaunchItem.Title, siteCollectionUrl.TrimEnd('/') + "/" + quickLaunchItem.Url.TrimStart('/'), quickLaunchItem.IsExternal);
				quickLaunch.AddAsLast(newQuickLaunchNode);
			}
			catch
			{
				newQuickLaunchNode = new SPNavigationNode(quickLaunchItem.Title, siteCollectionUrl.TrimEnd('/') + "/" + quickLaunchItem.Url.TrimStart('/'), true);
				quickLaunch.AddAsLast(newQuickLaunchNode);
			}

			if (newQuickLaunchNode != null)
			{
				foreach (var child in quickLaunchItem.Children)
				{
					ImportQuickLaunchItem(child, newQuickLaunchNode.Children, siteCollectionUrl);
				}
			}
		}
	}
}